﻿/* 2013/1/10 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Linq;

namespace Cosmos.Media.Play.IO
{
    /// <summary>
    /// Represents a reader that loads a play tree from a CPT file.
    /// </summary>
    public class CptReader : IPlayTreeReader, IDisposable
    {
        private const string _PlayTreeNodeElementName = "PlayTreeNode";
        private const string _PlayItemElementName = "PlayItem";
        private const string _NameAttributeName = "Name";
        private const string _PathAttributeName = "Path";
        private const string _TagElementName = "Tag";
        private const string _ValueAttributeName = "Value";
        private const string _AttributeAttributeName = "Attribute";
        private const string _InheritedAttributeName = "Inherited";
        private const string _MultipleAttributeName = "Multiple";

        private TextReader _textReader;
        private XmlReader _xmlReader;

        private string _defaultRootPath = null;

        public CptReader(TextReader textReader)
            : this(textReader, null)
        {

        }

        public CptReader(TextReader textReader, string defaultRootPath)
        {
            _textReader = textReader;
            if (defaultRootPath == null || Path.IsPathRooted(defaultRootPath))
            {
                _defaultRootPath = defaultRootPath;
            }
            else
            {
                throw new ArgumentException("The path is not rooted path.", "defaultRootPath");
            }
        }

        public CptReader(XmlReader xmlReader)
        {
            _xmlReader = xmlReader;
        }

        public void Close()
        {
            if (_textReader != null)
            {
                _textReader.Close();
            }

            if (_xmlReader != null)
            {
                _xmlReader.Close();
            }
        }

        public void Dispose()
        {
            if (_textReader != null)
            {
                _textReader.Dispose();
            }
        }

        public PlayTreeNode Load()
        {
            XDocument xDocument = null;
            if (_textReader != null)
            {
                xDocument = XDocument.Load(_textReader);
            }
            else if (_xmlReader != null)
            {
                xDocument = XDocument.Load(_xmlReader);
            }

            return LoadNodeFromXml(xDocument.Element(_PlayTreeNodeElementName));
        }

        private PlayTreeNode LoadNodeFromXml(XElement nodeElement)
        {
            string nodeName = nodeElement.Attribute(_NameAttributeName).Value;
            PlayTreeNode node = new PlayTreeNode(nodeName);

            // Reads all attributes.
            PlayAttribute attribute;
            string name;
            string value;
            bool inherited;
            bool multiple;
            foreach (XElement anElement in nodeElement.Elements(_AttributeAttributeName))
            {
                name = anElement.Attribute(_NameAttributeName).Value;
                value = anElement.Attribute(_ValueAttributeName).Value;
                inherited = Boolean.Parse(anElement.Attribute(_InheritedAttributeName).Value);
                multiple = Boolean.Parse(anElement.Attribute(_MultipleAttributeName).Value);

                attribute = new PlayAttribute(name, value)
                {
                    Inherited = inherited,
                    AllowMultiple = multiple,
                };
                node.Attributes.Add(attribute);
            }
            value = null;
            name = null;
            attribute = null;

            // Reads all sub-nodes.
            foreach (XElement anElement in nodeElement.Elements(_PlayTreeNodeElementName))
            {
                node.Nodes.Add(LoadNodeFromXml(anElement));
            }

            // Reads all items.
            foreach (XElement anElement in nodeElement.Elements(_PlayItemElementName))
            {
                node.List.Items.Add(LoadItemFromXml(anElement));
            }

            return node;
        }

        private PlayListItem LoadItemFromXml(XElement itemElement)
        {
            string itemName = itemElement.Attribute(_NameAttributeName).Value;
            string itemPath = itemElement.Attribute(_PathAttributeName).Value;
            if (!Path.IsPathRooted(itemPath) && _defaultRootPath != null)
            {
                itemPath = Path.Combine(_defaultRootPath, itemPath);
            }
            PlayListItem item = new PlayListItem(itemName, itemPath);

            // Reads all tags.
            string tag;
            foreach (XElement anElement in itemElement.Elements(_TagElementName))
            {
                tag = anElement.Attribute(_ValueAttributeName).Value;

                item.Tags.Add(tag);
            }
            tag = null;

            // Reads all attributes.
            PlayAttribute attribute;
            string name;
            string value;
            bool inherited;
            bool multiple;
            foreach (XElement anElement in itemElement.Elements(_AttributeAttributeName))
            {
                name = anElement.Attribute(_NameAttributeName).Value;
                value = anElement.Attribute(_ValueAttributeName).Value;
                inherited = Boolean.Parse(anElement.Attribute(_InheritedAttributeName).Value);
                multiple = Boolean.Parse(anElement.Attribute(_MultipleAttributeName).Value);

                attribute = new PlayAttribute(name, value)
                {
                    Inherited = inherited,
                    AllowMultiple = multiple,
                };
                item.Attributes.Add(attribute);
            }
            value = null;
            name = null;
            attribute = null;

            return item;
        }
    }
}
